import Logger from './Logger'

/**
 *  触发事件通用方法
 */

const newEvent = (type: string) => {
    return new Event(type, {
        bubbles: true,
        cancelable: true,
        composed: true,
    })
}

/**
 * 循环dispatch触发某些方法
 */

const dispatchEventByArray = (el: HTMLElement, events: string[]) => {
    if (!el) return
    events.forEach((event) => {
        el.dispatchEvent(newEvent(event))
    })
}

/**
 *  触发鼠标事件通用方法
 */

const newMouseEvent = (type: string) => {
    return new MouseEvent(type, {
        view: window,
        bubbles: true,
        cancelable: true,
    })
}

/**
 * 触发键盘通用方法
 * */

const newKeyboardEvent = (type: string, key: string, keyCode: number) => {
    return new KeyboardEvent(type, {
        keyCode: keyCode,
        key: key,
        bubbles: true,
        cancelable: true,
        composed: true,
    })
}

/**
 *  填写输入框内容，并且赋值给输入框（针对js和vue） setVueInput
 */

export const svInput = (el: HTMLInputElement, value: string) => {
    el.value = value
    dispatchEventByArray(el, ['input', 'change'])
}

/**
 *  填写输入框内容，并且赋值给输入框（针对react） setReactInput
 */
export const srInput = (el: HTMLSelectElement, value: string) => {
    const lastValue = el.value
    el.value = value
    const event = new Event('input', { bubbles: true })
    ;(event as any).simulated = true // 解决 simulated 属性问题
    el.dispatchEvent(event)
    dispatchEventByArray(el, ['focus', 'change', 'blur'])
    //@ts-ignore
    const tracker = el._valueTracker // 解决 _valueTracker 属性问题
    if (tracker) {
        tracker.setValue(lastValue)
    }
}

/**
 * 等待某个元素出现
 * 传四个参数 selector: string，timeout: number，interval: number，name: string
 * 解释： selector: string 选择器，timeout: number 超时时间，interval: number 间隔时间，name: string 元素名称
 * */

export const waitElementShow = (
    selector: string,
    timeout = 5000,
    interval = 5,
    name = '',
    parentNode = document,
) => {
    if (!selector) return console.error('请传入选择器')
    let timer: any
    let timeoutId: any
    const timeoutPromise = new Promise((_resolve, reject) => {
        timeoutId = setTimeout(() => {
            reject(new Error(`等待${name || selector}元素出现超时！`))
            clearInterval(timer) // 清除原始 Promise 中的定时器
        }, timeout)
    })
    const waitForElementPromise = new Promise((resolve, _reject) => {
        timer = setInterval(() => {
            Logger.prettyInfo('等待元素出现', name || selector, 'blue')
            if (parentNode.querySelector(selector)) {
                resolve(`${name || selector}元素出现了！`)
                clearInterval(timer)
                clearTimeout(timeoutId)
            }
        }, interval)
    })
    return Promise.race([waitForElementPromise, timeoutPromise])
}

/**
 * 等待某个元素消失
 * 传四个参数 selector: string，timeout: number，interval: number，name: string
 * 解释： selector: string 选择器，timeout: number 超时时间，interval: number 间隔时间，name: string 元素名称
 * */

export const waitElementHide = (
    selector: string,
    timeout = 5000,
    interval = 5,
    name = '',
    parentNode = document,
) => {
    if (!selector) return console.error('请传入选择器')
    let timer: any
    let timeoutId: any
    const timeoutPromise = new Promise((_resolve, reject) => {
        timeoutId = setTimeout(() => {
            reject(new Error(`等待${name || selector}元素消失超时！`))
            clearInterval(timer) // 清除原始 Promise 中的定时器
        }, timeout)
    })
    const waitForElementPromise = new Promise((resolve, _reject) => {
        timer = setInterval(() => {
            Logger.prettyInfo('等待元素消失', name || selector, 'blue')
            if (!parentNode.querySelector(selector)) {
                resolve(`${name || selector}元素消失了！`)
                clearInterval(timer)
                clearTimeout(timeoutId)
            }
        }, interval)
    })
    return Promise.race([waitForElementPromise, timeoutPromise])
}

/**
 * 等待指定时间单位ms
 * @param {number} ms
 * @returns Promise
 * */
export const sleep = (ms: number) => {
    return new Promise((resolve) => {
        setTimeout(resolve, ms)
    })
}

/**
 * 返回真正的数组选择元素querySelectorAll
 * */

export const querySelectorAll = (el: HTMLElement, selector: string) => {
    if (!el || !selector) return []
    return Array.from(el.querySelectorAll(selector))
}

/**
 * 触发元素点击的最终解决方案
 * */
export const triggerClick = (el: HTMLElement) => {
    el.dispatchEvent(newMouseEvent('mouseover'))
    el.dispatchEvent(newMouseEvent('mousedown'))
    el.dispatchEvent(newMouseEvent('mouseup'))
    el.click()
}

/**
 * 触发元素回车的最终解决方案
 * */
export const triggerEnter = (input: HTMLInputElement) => {
    // 让输入框获得焦点
    input.focus()
    input.dispatchEvent(newKeyboardEvent('keydown', 'Enter', 13))
    input.dispatchEvent(newKeyboardEvent('keyup', 'Enter', 13))
}

/**
 * 处理虚拟滚动table的方法自动滚动，并触发某些方法, 传入方法以及滚动条容器
*/
export const handleVirtualTable = async (fun, box) => {
    let lastScrollTop = box.scrollTop;
    let maxScrollTop = box.scrollHeight - box.clientHeight;

    // 循环滚动表格，直到没有更多数据加载
    while (lastScrollTop < maxScrollTop) {
        fun();
        box.scrollTop += box.clientHeight;
        await new Promise(resolve => setTimeout(resolve, 500)); // 等待数据加载完成
        lastScrollTop = box.scrollTop;
        maxScrollTop = box.scrollHeight - box.clientHeight;
    }

    // 处理最后一屏的数据
    fun();
}

/**
 * 网页自动上传文件
 * */

export const autoUploadFile = (
    fileInput,
    reqUrl,
    picUrl,
    fileName = 'cj_upload',
) => {
    return new Promise((resolve, reject) => {
        fetch(reqUrl, {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
            },
            body: JSON.stringify({
                url: picUrl,
            }),
        })
            .then((response) => {
                if (!response.ok) {
                    // 如果响应状态码不是200，抛出错误
                    reject(response.statusText)
                }
                return response.blob() // 将响应解析为 Blob
            })
            .then((data) => {
                const input = fileInput
                const dataTransfer = new DataTransfer()
                const file = createFile(data, picUrl, fileName)
                dataTransfer.items.add(file)
                input.files = dataTransfer.files
                const event = new Event('change', {
                    bubbles: true,
                    cancelable: true,
                    composed: true,
                })
                input.dispatchEvent(event)
                resolve('success')
            })
            .catch((error) => {
                console.error('Error:', error)
                reject(error)
            })
    })
}

const createFile = (data, originalFileName, fileName) => {
    // 从文件名中提取后缀
    const fileExtension = originalFileName.split('.').pop().toLowerCase()

    // 根据文件后缀设置 MIME 类型和文件名
    let mimeType
    let newFileName

    if (fileExtension === 'jpg' || fileExtension === 'jpeg') {
        mimeType = 'image/jpeg'
        newFileName = fileName + '.jpg'
    } else if (fileExtension === 'png') {
        mimeType = 'image/png'
        newFileName = fileName + '.png'
    } else {
        throw new Error('Unsupported file type')
    }

    // 创建新的 File 对象
    return new File([data], newFileName, { type: mimeType })
}
